package org.hawk.gwt.ppc.parser.impl;

import static org.hawk.gwt.ppc.parser.impl.DescriptorParserUtils.expect;
import static org.hawk.gwt.ppc.parser.impl.DescriptorParserUtils.lookupNext;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.hawk.gwt.ppc.parser.BlockDescriptor;
import org.hawk.gwt.ppc.parser.Descriptor;
import org.hawk.gwt.ppc.parser.ExpressionDescriptor;
import org.hawk.gwt.ppc.parser.Token;
import org.hawk.gwt.ppc.utils.PreprocessorException;

/**
 * Parses block of code (between { and } brackets).
 * Note that modifiers (if any) should be passed to this parser as parameters.
 * 
 * @author alex.bereznevatiy@gmail.com
 *
 */
final class BlockDescriptorParser implements DescriptorParser {

	/*
	 * (non-Javadoc)
	 * @see org.hawk.gwt.ppc.parser.impl.DescriptorParser#accepts(org.hawk.gwt.ppc.parser.Token)
	 */
	public boolean accepts(Token token) {
		return token.equalsTo('{');
	}

	/*
	 * (non-Javadoc)
	 * @see org.hawk.gwt.ppc.parser.impl.DescriptorParser#parse(org.hawk.gwt.ppc.parser.impl.TokenBasedJavaParser, org.hawk.gwt.ppc.parser.impl.Tokenizer, java.lang.Object[])
	 */
	@SuppressWarnings("unchecked")
	public Descriptor parse(TokenBasedJavaParser parser, TokenSource tokenizer, Object...params)
			throws PreprocessorException {
		Token first = tokenizer.current();
		lookupNext(tokenizer, false);
		List<Descriptor> descriptors = new ArrayList<Descriptor>();
		while (tokenizer.current().isComment()) {
			lookupNext(tokenizer, false);
		}
		while (!tokenizer.current().equalsTo('}')) {
			expect(parser, tokenizer, descriptors, DescriptorType.BLOCK, DescriptorType.LINE_EXPRESSION, 
					DescriptorType.BLOCK_EXPRESSION, DescriptorType.KEYWORD_EXPRESSION);
		}
		
		Token last = tokenizer.current();
		lookupNext(tokenizer, false);
		
		return new BlockDescriptorImpl(first, last, (List<String>) (params.length > 0 ? params[0] : Collections.emptyList()), 
				descriptors, (List<String>) (params.length > 1 ? params[1] : Collections.emptyList()));
	}

	/**
	 * 
	 * @author alex.bereznevatiy@gmail.com
	 *
	 */
	private static class BlockDescriptorImpl extends AbstractDescriptorContainer implements BlockDescriptor {
		
		private List<String> modifiers;
		private List<String> labels;

		BlockDescriptorImpl(Token first, Token last,
				List<String> modifiers, List<Descriptor> descriptors, List<String> labels) {
			super(first, last, descriptors);
			
			this.modifiers = Collections.unmodifiableList(modifiers);
			this.labels = labels;
		}

		/*
		 * (non-Javadoc)
		 * @see org.hawk.gwt.ppc.parser.ModificatedDescriptor#getModifiers()
		 */
		public List<String> getModifiers() {
			return modifiers;
		}

		/*
		 * (non-Javadoc)
		 * @see org.hawk.gwt.ppc.parser.BlockDescriptor#getLabels()
		 */
		public List<String> getLabels() {
			return labels;
		}
		
		/*
		 * (non-Javadoc)
		 * @see org.hawk.gwt.ppc.parser.impl.AbstractDescriptor#getParent()
		 */
		public ExpressionDescriptor getParent() {
			Descriptor parent = super.getParent();
			if (parent instanceof ExpressionDescriptor) {
				return (ExpressionDescriptor) parent;
			}
			return null;
		}
	}
}
